--
-- Shadow priest rotation helper
--

if _G.Rotor.player_class ~= 'PRIEST' then return end

-------------------------------------------
-- Local references to globals for speed and lint's happiness
-------------------------------------------
local Rotor = _G.Rotor

local UnitHealth = _G.UnitHealth
local UnitHealthMax = _G.UnitHealthMax
local strsplit = _G.strsplit
local max = _G.max
local GetTime = _G.GetTime

----------------------------------------
--
-- Module instance
--
local Mod = Rotor:NewModule('Shadow Priest')

-------------------------------------------
-- Constants
-------------------------------------------

--
-- Spell ids
--
local MB_ID     = 8092  -- mind blast
local SWP_ID    = 589   -- shadow word: pain
local VT_ID     = 34914 -- vampiric touch
local DP_ID     = 2944  -- devouring plague
local MF_ID     = 15407 -- mind flay
local SWD_ID    = 32379 -- shadow word: death

---------------------------------------------------------
--
-- Spell prediction
--

-- Local vars
local now = 0
local gcd = 0

--
-- Methods implementation
--

local spellAndAuraDefs = {
    shadow = {
        spec = 3,
        spells = {
            mb = MB_ID,
            swd = SWD_ID,
            swp = {SWP_ID, with_debuff = true},
            vt = {VT_ID, with_debuff = true},
            dp = {DP_ID, with_debuff = true},
        }
    }
}

local spells, buffs, debuffs

function Mod:Init(opts)
    spells, buffs, debuffs = Rotor:RegisterSpellsAndAuras(spellAndAuraDefs)
    return true
end

function Mod:Done()
    spells = nil
    buffs = nil
    debuffs = nil
end

local function CheckUnsent(spell, time_since_last_sent)
    return (spell.sentAt <= spell.doneAt) and (spell.doneAt + (time_since_last_sent or 0.5) < now)
end

local function CheckOffCdAndUnsent(spell, time_since_last_sent, wth)
    return (spell.cd - (wth or 0.4) <= gcd) and CheckUnsent(spell, time_since_last_sent)
end

local at_max_level = _G['UnitLevel']('player') == _G['MAX_PLAYER_LEVEL']
local dots_max_hp_threshold
if at_max_level then
    dots_max_hp_threshold = 300000
else
    dots_max_hp_threshold = 80000
end

function Mod:NextSkill(gcd_arg, cur_spell)
    gcd = max(0.5, gcd_arg)
    now = GetTime()

    local target_max_hp = UnitHealthMax('target')

    local use_dots = (target_max_hp > dots_max_hp_threshold)

    if (UnitHealth('target') / target_max_hp < 0.25) and CheckOffCdAndUnsent(spells.swd, 1.5) then
        return SWD_ID
    end

    if use_dots and (debuffs.vt.time_left < 2) and CheckUnsent(spells.vt, 2) then
        return VT_ID
    end

    if use_dots and (debuffs.dp.time_left < 2) and CheckUnsent(spells.dp, 2) then
        return DP_ID
    end

    if use_dots and (debuffs.swp.time_left < 2) and CheckUnsent(spells.swp, 2) then
        return SWP_ID
    end

    if CheckOffCdAndUnsent(spells.mb, 3) then
        return MB_ID
    end

    return MF_ID
end

-- Command line handler
function Mod:HandleCommandLine(cmd)
    local cmd, args = strsplit(' ', (cmd or ''):lower(), 2)
    -- handle command line here
end

-- Module detection
function Mod:Detect()
    return Rotor.spec == 3
end
